<template>
	<view class="tabs">
		<!-- 标签栏外层容器 -->
		<view class="tabs__container">
			<!-- 左侧插槽（如返回按钮） -->
			<slot name="left" class="tabs__slot-left" />

			<!-- 滚动容器（标签超出时可横向滚动） -->
			<view class="tabs__scroll-wrap">
				<scroll-view class="tabs__scroll" :scroll-x="scrollable" :scroll-left="scrollLeft" scroll-with-animation
					:show-scrollbar="false" ref="tabsScrollRef">
					<!-- 标签列表 -->
					<view class="tabs__nav" ref="tabsNavRef">
						<view class="tabs__nav-item" v-for="(item, index) in list" :key="index"
							@tap="handleTabClick(item, index)" @longpress="handleTabLongPress(item, index)"
							:ref="`tabsNavItemRef-${index}`" :style="[tabItemStyle, { flex: scrollable ? '' : 1 }]"
							:class="{ 
                                'tabs__nav-item--disabled': item.disabled,
                                'tabs__nav-item--active': !item.disabled && index === innerCurrent
                            }">
							<!-- 标签文本 -->
							<text class="tabs__nav-item__text"
								:style="[index === innerCurrent ? activeTextStyle : inactiveTextStyle]">
								{{ item[keyName] }}
							</text>

							<!-- 内置 Badge -->
							<view v-if="shouldShowBadge(item)" class="tabs__badge" :class="[
                                    `tabs__badge--${getBadgeConfig(item, 'type')}`,
                                    `tabs__badge--${getBadgeConfig(item, 'shape')}`,
                                    {
                                        'tabs__badge--dot': getBadgeConfig(item, 'isDot'),
                                        'tabs__badge--inverted': getBadgeConfig(item, 'inverted'),
                                        'tabs__badge--zero': getBadgeConfig(item, 'showZero') && getBadgeConfig(item, 'value') === 0
                                    }
                                ]" :style="[
                                    { marginLeft: '0px' },
                                    getBadgeConfig(item, 'bgColor') ? { backgroundColor: getBadgeConfig(item, 'bgColor') } : {},
                                    getBadgeConfig(item, 'color') ? { color: getBadgeConfig(item, 'color') } : {},
									getBadgeConfig(item, 'isDot')?{right:'8rpx',top:'20rpx'}:{}
                                ]">
								<!-- Badge 内容：dot模式显示圆点，否则显示格式化数值 -->
								<template v-if="getBadgeConfig(item, 'isDot')">
									<view class="tabs__badge__dot-inner"></view>
								</template>
								<template v-else>
									{{ formatBadgeValue(getBadgeConfig(item, 'value'), getBadgeConfig(item, 'max')) }}
								</template>
							</view>
						</view>

						<!-- 下划线滑块（多端兼容动画） -->
						<view class="tabs__nav-line" ref="tabsNavLineRef" :style="[
                                { 
                                    width: addUnit(lineWidth),
                                    height: addUnit(lineHeight),
                                    background: lineColor,
                                    borderRadius: addUnit(lineHeight / 2),
                                    position: 'absolute',
                                    bottom: 0
                                },
                                !isNVUE ? { 
                                    transform: `translateX(${lineOffsetLeft}px)`,
                                    transition: `transform ${firstRender ? 0 : duration}ms ease`
                                } : {}
                            ]"></view>
					</view>
				</scroll-view>
			</view>

			<!-- 右侧插槽（如搜索按钮） -->
			<slot name="right" class="tabs__slot-right" />
		</view>
	</view>
</template>

<script>
	// 多端环境判断
	const isNVUE = uni.getSystemInfoSync().platform === 'devtools' ?
		false :
		typeof weex !== 'undefined';

	// NVUE 原生动画引入（仅在 App 端生效）
	let animation = null;
	if (isNVUE) {
		animation = uni.requireNativePlugin('animation');
	}

	export default {
		name: 'Tabs',
		props: {
			// 标签列表（必传）
			list: {
				type: Array,
				required: true,
				default: () => []
			},
			// 当前激活标签索引
			current: {
				type: Number,
				default: 0
			},
			// 是否可横向滚动（标签超出时）
			scrollable: {
				type: Boolean,
				default: true
			},
			// 标签文本字段名（从 list 项中读取文本）
			keyName: {
				type: String,
				default: 'name'
			},
			// 下划线宽度
			lineWidth: {
				type: [Number, String],
				default: 20
			},
			// 下划线高度
			lineHeight: {
				type: [Number, String],
				default: 3
			},
			// 下划线颜色
			lineColor: {
				type: String,
				default: '#3c9cff'
			},
			// 切换动画时长（ms）
			duration: {
				type: Number,
				default: 200
			},
			// 激活标签文本样式
			activeTextStyle: {
				type: [String, Object],
				default: () => ({
					color: '#3c9cff',
					fontWeight: '500'
				})
			},
			// 未激活标签文本样式
			inactiveTextStyle: {
				type: [String, Object],
				default: () => ({
					color: '#606266'
				})
			},
			// 标签项基础样式
			tabItemStyle: {
				type: [String, Object],
				default: () => ({
					padding: '0 14px',
					height: '44px'
				})
			}
		},
		data() {
			return {
				innerCurrent: this.current, // 内部维护的激活索引（避免直接修改props）
				scrollLeft: 0, // 滚动容器的滚动偏移量
				lineOffsetLeft: 0, // 下划线滑块的水平偏移量
				firstRender: true, // 是否首次渲染（首次无动画）
				isNVUE, // 多端环境标识
				// Badge 默认配置（与原 u-badge 对齐）
				badgeDefault: {
					isDot: false,
					value: '',
					show: true,
					max: 99,
					type: 'error',
					showZero: false,
					bgColor: '',
					color: '#fff',
					shape: 'circle',
					inverted: false
				}
			};
		},
		watch: {
			// 监听外部传入的 current 变化，同步更新内部索引
			current: {
				immediate: false,
				handler(newVal) {
					if (newVal !== this.innerCurrent && !this.list[newVal]?.disabled) {
						this.innerCurrent = newVal;
						this.updateTabsLayout(); // 同步更新布局（下划线+滚动）
					}
				}
			},
			// 监听内部索引变化，触发下划线和滚动更新
			innerCurrent() {
				this.updateTabsLayout();
				// 延迟关闭首次渲染标识（确保首次切换有动画）
				if (this.firstRender) {
					setTimeout(() => (this.firstRender = false), 100);
				}
			},
			// 监听标签列表变化，重新计算布局
			list: {
				deep: true,
				handler() {
					this.$nextTick(() => this.updateTabsLayout());
				}
			}
		},
		mounted() {
			// 首次渲染后计算布局
			this.$nextTick(() => {
				this.updateTabsLayout();
				// 延迟关闭首次渲染标识（避免首次加载动画）
				setTimeout(() => (this.firstRender = false), 300);
			});
		},
		methods: {
			// ---------------------- 标签交互 ----------------------
			// 点击标签
			handleTabClick(item, index) {
				if (item.disabled) return; // 禁用标签不响应点击
				// 触发外部点击事件
				this.$emit('click', {
					item,
					index
				});
				// 若索引变化，更新内部激活状态
				if (index !== this.innerCurrent) {
					this.innerCurrent = index;
					// 触发外部切换事件
					this.$emit('change', index);
				}
			},

			// 长按标签
			handleTabLongPress(item, index) {
				if (item.disabled) return;
				this.$emit('longpress', {
					item,
					index
				});
			},

			// ---------------------- 布局更新 ----------------------
			// 更新标签栏布局（下划线位置 + 滚动位置）
			updateTabsLayout() {
				Promise.all([
					this.getNavItemRects(), // 获取所有标签项的尺寸
					this.getScrollContainerRect() // 获取滚动容器的尺寸
				]).then(([itemRects, scrollRect]) => {
					if (!itemRects.length || !scrollRect) return;
					// 更新下划线位置
					this.updateLineOffset(itemRects);
					// 更新滚动位置（确保激活标签居中）
					this.updateScrollPosition(itemRects, scrollRect);
				});
			},

			// 获取所有标签项的尺寸和位置
			getNavItemRects() {
				return new Promise(resolve => {
					const itemRefs = this.list.map((_, i) => this.$refs[`tabsNavItemRef-${i}`]?.[0] || this.$refs[
						`tabsNavItemRef-${i}`]);
					if (isNVUE) {
						// NVUE 用原生方法获取节点信息
						const dom = uni.requireNativePlugin('dom');
						dom.getComponentRect(itemRefs, res => {
							resolve(res.rects.filter(rect => rect));
						});
					} else {
						// 非 NVUE 用 uni.createSelectorQuery
						uni.createSelectorQuery().in(this)
							.selectAll('.tabs__nav-item')
							.boundingClientRect(rects => {
								resolve(rects.filter(rect => rect));
							})
							.exec();
					}
				});
			},

			// 获取滚动容器的尺寸
			getScrollContainerRect() {
				return new Promise(resolve => {
					const scrollRef = this.$refs.tabsScrollRef;
					if (isNVUE) {
						const dom = uni.requireNativePlugin('dom');
						dom.getComponentRect(scrollRef, res => {
							resolve(res.rect || {});
						});
					} else {
						uni.createSelectorQuery().in(this)
							.select('.tabs__scroll')
							.boundingClientRect(rect => {
								resolve(rect || {});
							})
							.exec();
					}
				});
			},

			// 更新下划线滑块位置
			updateLineOffset(itemRects) {
				const activeRect = itemRects[this.innerCurrent];
				if (!activeRect) return;
				// 计算下划线偏移：标签左侧距离 + 标签半宽 - 下划线半宽（实现居中）
				const lineWidth = this.parseToNumber(this.lineWidth);
				this.lineOffsetLeft = activeRect.left + (activeRect.width - lineWidth) / 2;

				// NVUE 用原生动画更新位置（非 NVUE 用 CSS transition）
				if (isNVUE && !this.firstRender) {
					animation.transition(this.$refs.tabsNavLineRef, {
						styles: {
							transform: `translateX(${this.lineOffsetLeft}px)`
						},
						duration: this.duration,
						timingFunction: 'ease'
					});
				}
			},

			// 更新滚动位置（激活标签居中）
			updateScrollPosition(itemRects, scrollRect) {
				const activeRect = itemRects[this.innerCurrent];
				if (!activeRect || !this.scrollable) return;

				// 计算激活标签在滚动容器中的相对位置
				const navRef = this.$refs.tabsNavRef;
				const navLeft = isNVUE ? navRef.getBoundingClientRect().left : 0;
				const activeRelativeLeft = activeRect.left - navLeft;

				// 计算需要的滚动偏移：让激活标签居中
				const targetScrollLeft = activeRelativeLeft - (scrollRect.width - activeRect.width) / 2;
				// 限制滚动范围（避免负滚动或超出最大滚动距离）
				const maxScrollLeft = itemRects.reduce((sum, rect) => sum + rect.width, 0) - scrollRect.width;
				this.scrollLeft = Math.max(0, Math.min(targetScrollLeft, maxScrollLeft));
			},

			// ---------------------- 工具方法 ----------------------
			// 样式转换（字符串 ↔ 对象）
			parseStyle(style) {
				if (typeof style === 'object') return style;
				if (typeof style !== 'string') return {};

				// 字符串转对象（如 "font-size:14px;color:red" → { fontSize: '14px' }）
				return style.split(';')
					.filter(item => item.trim())
					.reduce((obj, item) => {
						const [key, value] = item.split(':').map(i => i.trim());
						const camelKey = key.replace(/-(\w)/g, (_, w) => w.toUpperCase());
						obj[camelKey] = value;
						return obj;
					}, {});
			},

			// 转换为数字（处理 rpx/px 单位）
			parseToNumber(value) {
				if (typeof value === 'number') return value;
				if (typeof value !== 'string') return 0;

				// 提取数字（支持 rpx/px 单位）
				const num = parseFloat(value.replace(/[a-zA-Z]+/g, ''));
				return isNaN(num) ? 0 : num;
			},

			// 添加单位（默认 px，已带单位则不处理）
			addUnit(value, unit = 'px') {
				if (typeof value === 'number') return `${value}${unit}`;
				if (typeof value === 'string' && /[a-zA-Z]+$/.test(value)) return value;
				return `${value}${unit}`;
			},

			// ---------------------- 内置 Badge 方法 ----------------------
			// 判断 Badge 是否显示
			shouldShowBadge(item) {
				const badge = item.badge || {};
				// 满足以下任一条件显示：1. show为true 2. dot模式 3. 有数值（且showZero时0也显示）
				return badge.show !== false &&
					(badge.isDot || (badge.value !== '' && (badge.showZero || this.parseToNumber(badge.value) !== 0)));
			},

			// 获取 Badge 配置（优先 item.badge，无则用默认值）
			getBadgeConfig(item, key) {
				const badge = item.badge || {};
				return badge[key] !== undefined ? badge[key] : this.badgeDefault[key];
			},

			// 格式化 Badge 数值（超过 max 显示 "max+"）
			formatBadgeValue(value, max) {
				const numValue = this.parseToNumber(value);
				const numMax = this.parseToNumber(max);

				if (isNaN(numValue) || isNaN(numMax) || numValue <= numMax) {
					return value;
				}
				return `${numMax}+`;
			}
		}
	};
</script>

<style scoped lang="scss">
	// 基础样式变量
	$tabs-height: 44px;
	$text-inactive: #606266;
	$text-active: #3c9cff;
	$line-color: #3c9cff;

	// 标签栏外层容器
	.tabs {
		width: 100%;
		box-sizing: border-box;
		background-color: #fff;
	}

	// 标签栏容器（包含左右插槽和滚动区）
	.tabs__container {
		display: flex;
		align-items: center;
		height: $tabs-height;
		overflow: hidden;
	}

	// 左右插槽（默认隐藏，有内容时显示）
	.tabs__slot-left,
	.tabs__slot-right {
		flex-shrink: 0;
		padding: 0 8px;
		height: 100%;
		display: flex;
		align-items: center;
	}

	// 滚动容器（限制高度，避免超出）
	.tabs__scroll-wrap {
		flex: 1;
		height: 100%;
		overflow: hidden;
	}

	// 滚动视图（横向滚动）
	.tabs__scroll {
		width: 100%;
		height: 100%;
		white-space: nowrap; // 确保标签不换行
	}

	// 标签列表容器（相对定位，用于下划线绝对定位）
	.tabs__nav {
		position: relative;
		display: inline-flex;
		align-items: center;
		height: 100%;
		width: 100%;
	}

	// 单个标签项
	.tabs__nav-item {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		box-sizing: border-box;
		cursor: pointer;
		transition: all 0.2s ease;
		position: relative;

		&--disabled {
			cursor: not-allowed;
			opacity: 0.6;
		}

		&--active {
			// 激活状态的额外样式（可通过 props 覆盖）
		}
	}

	// 标签文本
	.tabs__nav-item__text {
		font-size: 15px;
		transition: color 0.2s ease;
	}

	// 下划线滑块
	.tabs__nav-line {
		background-color: $line-color;
		transition-property: transform;
		transition-timing-function: ease;
	}

	// ---------------------- 内置 Badge 样式 ----------------------
	.tabs__badge {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		min-width: 18px;
		font-size: 20rpx;
		box-sizing: border-box;
		transform: translateY(-2px);
		position: absolute;
		padding: 2rpx;
		right: -8rpx;
		height: fit-content;
		top: 15rpx;

		.tabs__badge__dot-inner {}

		// 形状：圆形/方形
		&--circle {
			border-radius: 9px;
		}

		&--square {
			border-radius: 2px;
		}

		// 类型：不同颜色
		&--error {
			background-color: #f53f3f;
		}

		&--success {
			background-color: #00b42a;
		}

		&--warning {
			background-color: #ff7d00;
		}

		&--info {
			background-color: #86909c;
		}

		// 点模式（小圆点）
		&--dot {
			width: 8px;
			height: 8px;
			min-width: auto;
			padding: 0;
		}

		// 点模式内部圆点
		&__dot-inner {
			width: 6px;
			height: 6px;
			border-radius: 50%;
			background-color: currentColor;
		}

		// 反向模式（边框+透明背景）
		&--inverted {
			background-color: transparent;
			border: 1px solid currentColor;
		}

		// 零值显示（默认隐藏0值）
		&:not(&--zero) {
			&[data-value="0"] {
				display: none;
			}
		}
	}
</style>